package vcp.client.GUI.mvc.view.custom;

import java.awt.Component;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JButton;
import javax.swing.plaf.synth.SynthSpinnerUI;
/**
 * <p> custom spinner user interface class </p>
 * @author VCP team
 *
 */
public class CustomSpinnerUI extends SynthSpinnerUI
{
	private final ActionListener incrementUI;
	private final ActionListener decrementUI;
	/**
	 * constructor
	 * @param incrementHandler
	 * @param decrementHandler
	 */
	public CustomSpinnerUI ( ActionListener incrementHandler, ActionListener decrementHandler )
	{
		super();
		this.incrementUI = incrementHandler;
		this.decrementUI = decrementHandler;
	}

	@Override
	protected void installNextButtonListeners ( Component c )
	{
		JButton nextButton = (JButton) c;
		nextButton.addMouseListener(new MouseRoutedCommand(this.incrementUI));
	}

	@Override
	protected void installPreviousButtonListeners ( Component c )
	{
		JButton previousButton = (JButton) c;
		previousButton.addMouseListener(new MouseRoutedCommand(this.decrementUI));
	}
	/**
	 * <p> private class mouse routed command </p>
	 * @author VCP team
	 *
	 */
	private class MouseRoutedCommand extends MouseAdapter
	{
		private static final long CLICK_LAG = 100;
		private boolean mouseIsHeldDown;
		private final ActionListener listener;

		private Timer timer;
		/**
		 * constructor
		 * @param listener
		 */
		public MouseRoutedCommand ( ActionListener listener )
		{
			this.listener = listener;
		}
		/**
		 * check if mouse held down on button
		 * @return ture if success
		 */
		public boolean isMouseHeldDownOnButton ()
		{
			return this.mouseIsHeldDown;
		}

		private void cancelTimer ()
		{
			if ( this.timer != null )
			{
				this.timer.cancel();
				this.timer = null;
			}
		}
		/**
		 * fire mouse hold button method
		 */
		private void fireMouseHeldDown ()
		{
			this.listener.actionPerformed(null);
		}

		@Override
		public void mousePressed ( MouseEvent arg0 )
		{
			this.cancelTimer();
			this.mouseIsHeldDown = true;
			this.timer = new Timer();
			this.timer.schedule(new MouseHeldDownTask(this), MouseRoutedCommand.CLICK_LAG);
		}

		@Override
		public void mouseReleased ( MouseEvent arg0 )
		{
			this.mouseIsHeldDown = false;
		}
		/**
		 * <p> private class mouse held down task </p>
		 * @author VCP team
		 *
		 */
		private class MouseHeldDownTask extends TimerTask
		{
			private static final long INITIAL_FIRE_DELAY = 100;
			private static final double FIRE_DELAY_STEP_MULTIPLIER = 110;
			private static final long MIN_FIRE_DELAY = 100;

			private final MouseRoutedCommand mouseDelegate;
			/**
			 * constructor
			 * @param mouseDelegate
			 */
			public MouseHeldDownTask ( MouseRoutedCommand mouseDelegate )
			{
				this.mouseDelegate = mouseDelegate;
			}

			@Override
			public void run ()
			{
				long delay = MouseHeldDownTask.INITIAL_FIRE_DELAY;
				do
				{
					this.mouseDelegate.fireMouseHeldDown();

					try
					{
						Thread.sleep(delay);
					}
					catch ( InterruptedException e )
					{
						e.printStackTrace();
					}

					if ( delay > MouseHeldDownTask.MIN_FIRE_DELAY )
					{
						final long decrease = Math.round(MouseHeldDownTask.FIRE_DELAY_STEP_MULTIPLIER * Math.pow(MouseHeldDownTask.INITIAL_FIRE_DELAY / delay, 2));
						delay = Math.max(delay - decrease, MouseHeldDownTask.MIN_FIRE_DELAY);
					}
				} while ( this.mouseDelegate.isMouseHeldDownOnButton() );
			}
		}
	}

}
